package com.gaoding.qa.auto.base;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.gaoding.qa.auto.annotation.TestObject;
import com.gaoding.qa.auto.data.TestJavaObject;
import com.gaoding.qa.auto.interceptor.CoreInterceptor;
import com.gaoding.qa.auto.listener.MyListener;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.BeforeSuite;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Listeners;

import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.ParameterizedType;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author mobai
 * @since 2021/9/12 16:12
 */
@Listeners({MyListener.class})
@Slf4j
public class BaseApiTest extends AbstractTestNGSpringContextTests {

    private static final Logger logger = LoggerFactory.getLogger(BaseApiTest.class);
    private static final String BANNER = " \n   _____             _____  _             \n  / ____|           |  __ \\(_)            \n | |  __  __ _  ___ | |  | |_ _ __   __ _ \n | | |_ |/ _` |/ _ \\| |  | | | '_ \\ / _` |\n | |__| | (_| | (_) | |__| | | | | | (_| |\n  \\_____|\\__,_|\\___/|_____/|_|_| |_|\\__, |\n                                     __/ |\n                                    |___/ ";


    public BaseApiTest() {
    }


    public static void init() {
        logger.info(" \n   _____             _____  _             \n  / ____|           |  __ \\(_)            \n | |  __  __ _  ___ | |  | |_ _ __   __ _ \n | | |_ |/ _` |/ _ \\| |  | | | '_ \\ / _` |\n | |__| | (_| | (_) | |__| | | | | | (_| |\n  \\_____|\\__,_|\\___/|_____/|_|_| |_|\\__, |\n                                     __/ |\n                                    |___/ ");
    }

    @BeforeSuite
    public void before() {
        init();
    }



    @DataProvider
    public Object[][] object(Method m) throws IOException {
        if (!m.isAnnotationPresent(TestObject.class)) {
            throw new RuntimeException("java对象测试方法需要标注@TestObject注解！");
        }

        TestObject annotation = m.getAnnotation(TestObject.class);
        if (!annotation.isNeedData()) {
            return new Object[0][];
        }
        Parameter[] parameters = m.getParameters();
        if (parameters == null || parameters.length == 0) {
            log.error("方法无定义入参，请检查");
            return new Object[0][];
        }
        ClassPathResource re = new ClassPathResource(annotation.prefix()+"/" + annotation.value());
        try {
            String s = IOUtils.toString(re.getInputStream(), "utf-8");
            List<TestJavaObject> testJavaObjects = JSONArray.parseArray(s, TestJavaObject.class);
            testJavaObjects = testJavaObjects.stream().filter(data -> !data.isIgnore()).collect(Collectors.toList());
            Object[][] result = new Object[testJavaObjects.size()][];
            for (int i = 0; i < testJavaObjects.size(); i++) {
                TestJavaObject testJavaObject = testJavaObjects.get(i);
                Object[] param = new Object[parameters.length];
                Map<String, Object> data = testJavaObject.getData();
                if (data.size() != parameters.length) {
                    log.error("方法参数与实际数据个数不匹配");
                    throw new RuntimeException("方法参数与实际数据个数不匹配");
                }
                for (int i1 = 0; i1 < parameters.length; i1++) {
                    if (data.containsKey(parameters[i1].getName())) {
                        Parameter parameter = parameters[i1];
                        Class<?> type = parameter.getType();
                        Object o = data.get(parameters[i1].getName());
                        if (o.getClass() == type) {
                            param[i1] = o;
                        } else if(type.equals(List.class)){
                            ParameterizedType paramType= (ParameterizedType) parameter.getParameterizedType();
                            param[i1]=JSON.parseArray(JSON.toJSONString(o),(Class)paramType.getActualTypeArguments()[0]);
                        }else {
                            param[i1] = JSON.parseObject(JSON.toJSONString(o), type);
                        }

                    }
                }
                String className = m.getDeclaringClass().getName();
                CoreInterceptor.MAP.put(className + "#" + m.getName() + "@" + i, testJavaObject);
                result[i] = param;
            }
            return result;
        } catch (Exception e) {
            log.error("数据源绑定失败,method:{},file:{}", m.getName(), re.getPath());
        }
        log.error("无数据源，请检查是否预设数据");
        return null;

    }

    @BeforeMethod
    public void beforeTest() {
        log.info("测试开始");
    }




}